package com.defangit.production.orm;


import com.defangit.production.bll.TransferEntryBll;
import com.defangit.production.domain.*;
import laogen.hibernate.CommonFinder;
import laogen.hibernate.CommonService;
import laogen.lang.exception.ParameterNotValidException;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import java.time.LocalDateTime;


public class TransferEntryService extends CommonService<TransferEntry> implements TransferEntryBll {
    public TransferEntry addTransferEntry(TransferEntry transferEntry,Integer applicantId,Integer receiverId,Integer origin,Integer target){
        AbstractStore originStore = new AbstractStoreService().get(origin).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("出货仓库实体异常"));
        AbstractStore targetStore = new AbstractStoreService().get(target).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("收货仓库实体异常"));
        Operator applicant = new OperatorService().get(applicantId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("调拨单申请人信息异常"));
        Operator receiver = new OperatorService().get(receiverId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("接受人信息异常"));
        transferEntry.setCreateTime(LocalDateTime.now())
                .setApplicant(applicant)
                .setReceiver(receiver)
                .setOriginStore(originStore)
                .setTargetStore(targetStore);
        checkStock(transferEntry);
        add(transferEntry);
        commitSession();
        return get(transferEntry.getId()).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("库存转调拨录异常"));
    }

    /**
     * 根据领料单直接下单，（人工审核后）
     * */
    public TransferEntry addTransEntry(Integer materialId,Integer operatorId){
        Operator operator = new OperatorService().get(operatorId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("库管信息错误"));
        MaterialBill materialBill = new MaterialBillService().get(materialId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("领料单信息异常"));
        materialBill.setStoreKeeper(operator);
        TransferEntry transferEntry = new TransferEntry()
                .setAccept(true)
                .setApplicant(operator)
                .setCreateTime(LocalDateTime.now())
                .setEndTime(LocalDateTime.now())
                .setOriginStore(operator.getStore())
                .setTargetStore(materialBill.getProcess().getWorkShop());
        transferEntry.getManufactureItems().addAll(materialBill.getItems());
        checkStock(transferEntry);
        transferEntry.getManufactureItems().forEach(manufactureItem -> {
            Stock stock = new StockService()
                    .findAll()
                    .manufactureId(manufactureItem.getManufacture().getId())
                    .storeId(transferEntry.getTargetStore().getId())
                    .unique()
                    .orElse(null);
            if (stock==null){
                stock = new Stock().setManufacture(manufactureItem.getManufacture()).setStore(transferEntry.getTargetStore());
                getSession().save(stock);
            }
            StockAlteration stockAlterationAdd = new StockAlteration()
                    .setCreateTime(LocalDateTime.now())
                    .setFlag(0)
                    .setManufacture(manufactureItem.getManufacture())
                    .setQuantity(manufactureItem.getQuantity())
                    .setStore(transferEntry.getTargetStore());
            getSession().save(stockAlterationAdd);
            StockAlteration stockAlterationReduce = new StockAlteration()
                    .setCreateTime(LocalDateTime.now())
                    .setFlag(1)
                    .setManufacture(manufactureItem.getManufacture())
                    .setQuantity(-manufactureItem.getQuantity())
                    .setStore(transferEntry.getOriginStore());
            getSession().save(stockAlterationReduce);
        });
        add(transferEntry);
        getSession().update(materialBill);
        commitSession();
        return get(transferEntry.getId()).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("调拨单信息异常"));
    }


    public TransferEntry updateTransEntry(Integer transferId,Integer receiverId){
        Operator receiver = new OperatorService().get(receiverId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("用户信息异常"));
        TransferEntry transferEntry = get(transferId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("库存调拨记录信息异常"));
        if (transferEntry.getReceiver().getId()!=receiver.getId()) throw ParameterNotValidException.constraintNotSatisfy("该用户没有权限进行此操作","与调拨单接收人信息不匹配");
        transferEntry.setAccept(true).setEndTime(LocalDateTime.now());
        transferEntry.getManufactureItems().forEach(manufactureItem -> {
            Stock stock = new StockService()
                    .findAll()
                    .manufactureId(manufactureItem.getManufacture().getId())
                    .storeId(transferEntry.getTargetStore().getId())
                    .unique()
                    .orElse(null);
            if (stock==null){
                stock = new Stock().setManufacture(manufactureItem.getManufacture()).setStore(transferEntry.getTargetStore());
                getSession().save(stock);
            }
            StockAlteration stockAlterationAdd = new StockAlteration()
                    .setCreateTime(LocalDateTime.now())
                    .setFlag(0)
                    .setManufacture(manufactureItem.getManufacture())
                    .setQuantity(manufactureItem.getQuantity())
                    .setStore(transferEntry.getTargetStore());
            getSession().save(stockAlterationAdd);
            StockAlteration stockAlterationReduce = new StockAlteration()
                    .setCreateTime(LocalDateTime.now())
                    .setFlag(1)
                    .setManufacture(manufactureItem.getManufacture())
                    .setQuantity(-manufactureItem.getQuantity())
                    .setStore(transferEntry.getOriginStore());
            getSession().save(stockAlterationReduce);

        });
        update(transferEntry);
        commitSession();
        return get(transferId).orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist("库存转调拨录异常"));
    }

    private void checkStock(TransferEntry transferEntry){
        transferEntry.getManufactureItems().forEach(manufactureItem -> {
            Stock stock = new StockService()
                    .findAll()
                    .manufactureId(manufactureItem.getManufacture().getId())
                    .storeId(transferEntry.getOriginStore().getId())
                    .unique()
                    .orElseThrow(()->ParameterNotValidException.zeroIdOrEntityNonExist(manufactureItem.getManufacture().getManufactureName()+"库存物品信息不存在"));
            if (stock.getQuantity()<manufactureItem.getQuantity()) throw ParameterNotValidException
                    .constraintNotSatisfy(manufactureItem.getManufacture().getManufactureName()+"库存不足","the quantity is invalid");
        });
    }

    @Override
    public TransferEntryFinder findAll() {
        return new TransferEntryFinderImp();
    }

    public class TransferEntryFinderImp extends CommonFinder<TransferEntry> implements TransferEntryFinder {
        private DetachedCriteria transferCriteria;

        private TransferEntryFinderImp(){
            this.transferCriteria = detachedAll();
        }

        @Override
        public TransferEntryFinder transfetId(Integer id) {
            return null;
        }

        @Override
        public TransferEntryFinder accept(Boolean accept) {
            return null;
        }

        @Override
        public TransferEntryFinder applicantId(Integer id) {
            return null;
        }

        @Override
        public TransferEntryFinder receiverId(Integer id) {
            return null;
        }

        @Override
        public TransferEntryFinder storeId(Integer id) {
            return null;
        }

        @Override
        public Criteria getCriteria() {
            return this.transferCriteria.getExecutableCriteria(getSession()).addOrder(Order.desc("id"));
        }

        @Override
        public DetachedCriteria getDetachedCriteria() {
            return this.transferCriteria;
        }
    }
}
